package org.fzkj.rpc.core.client;

import org.fzkj.rpc.core.protocol.RequestProtocol;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * rpc框架客户端
 */
public class RPCClient {

    /**
     * 获取远程服务上的 对应接口的实例
     * @param interfaceClass 接口名称
     * @param address 服务地址
     * @param <T>
     * @return
     */
    public static <T> T getRemoteProxy(Class<T> interfaceClass, InetSocketAddress address){
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
                new Class<?>[]{interfaceClass}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /**
                         * 第一步：连接远程服务
                         */
                        try (Socket socket = new Socket()) {
                            // 连接
                            socket.connect(address);
                            //
                            try (
                                    // 获取输出流
                                    ObjectOutputStream serializer = new ObjectOutputStream(socket.getOutputStream());
                                    // 获取输入流
                                    ObjectInputStream deSerializer = new ObjectInputStream(socket.getInputStream());
                                    ) {
                                // 构建需要传递的请求协议对象
                                RequestProtocol reqProtocol = new RequestProtocol(interfaceClass.getName(),
                                        method.getName(), method.getParameterTypes(), args);
                                // 通过输出流放到网络中
                                serializer.writeObject(reqProtocol);

                                // 等待远程服务的返回
                                Object result = deSerializer.readObject();
                                return result;
                            }
                        }catch(Exception e){
                            e.printStackTrace();
                        }
                        return null;
                    }
                });
    }

}
